﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Text;

namespace MaterialTypeRecognition.Shell.AuthenticationServices.Extensions
{
    public static class JwtExtensions
    {
        public static IServiceCollection AddJwtBearerService(this IServiceCollection services, IConfiguration configuration)
        {
            // 从配置文件中获取 JWT 配置。
            var jwtConfig = configuration.GetSection("Jwt");
            // 获取密钥并生成公钥。
            var symmetricKeyAsBase64 = jwtConfig.GetValue<string>("Secret") ?? throw new InvalidOperationException();
            var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey = new SymmetricSecurityKey(keyByteArray);

            // 配置认证参数。
            services.AddAuthentication("Bearer")
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuerSigningKey = true,    // 是否验证签名,不验证的画可以篡改数据，不安全。
                        IssuerSigningKey = signingKey,      // 公钥。
                        ValidateIssuer = true,              // 是否验证发行人，就是验证载荷中的Iss是否对应ValidIssuer参数。
                        ValidIssuer = jwtConfig.GetValue<string>("Iss"),    // 发行人。
                        ValidateAudience = true,                            // 是否验证订阅人，就是验证载荷中的Aud是否对应ValidAudience参数。
                        ValidAudience = jwtConfig.GetValue<string>("Aud"),  // 订阅人。
                        ValidateLifetime = true,                            // 是否验证过期时间，过期了就拒绝访问。
                        ClockSkew = TimeSpan.Zero,    //这个是缓冲过期时间，也就是说，即使我们配置了过期时间，这里也要考虑进去，过期时间+缓冲，默认好像是7分钟，你可以直接设置为0。
                        RequireExpirationTime = true, // 设置需要过期时间。
                    };
                });

            services.AddAuthorization(options =>
            {
                options.AddPolicy(UserPermissoins.Users.Admin, policy =>
                {
                    policy.AddRequirements(new AdminPermissionRequirement())
                          .RequireClaim("Permission");
                });

                options.AddPolicy(UserPermissoins.Users.PE, policy =>
                {
                    policy.AddRequirements(new PEPermissionRequirement())
                          .RequireClaim("Permission");
                });

                options.AddPolicy(UserPermissoins.Users.ME, policy =>
                {
                    policy.AddRequirements(new MEPermissionRequirement())
                          .RequireClaim("Permission");
                });

                options.AddPolicy(UserPermissoins.Users.OPNMonitor, policy =>
                {
                    policy.AddRequirements(new OPNMonitorPermissionRequirement())
                          .RequireClaim("Permission");
                });

                options.AddPolicy(UserPermissoins.Users.OPN, policy =>
                {
                    policy.AddRequirements(new OPNPermissionRequirement())
                          .RequireClaim("Permission");
                });
            });

            return services;
        }
    }
}
